#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys, thread, os, random, time
import Ice, IceStorm

try:
    HOME = os.environ['ROBOTS']
except KeyError:
    print 'ROBOTS environment variable is not currently defined.'
    sys.exit(0)

SLICE = os.path.join(HOME, 'slice')
FILE = os.path.join(SLICE, 'Robots.ice')
Ice.loadSlice('--all -I/usr/share/slice', ['-I' + SLICE, FILE])

KB = os.path.join(HOME, 'kb', 'Robots.xml')

import Robots
import Util
import Fuzzy
from Fuzzy import *

class AMI_Model_receiveBidI (object):

    def ice_response (self):
        pass

    def ice_exception (self, ex):
        pass

class AgentI (Robots.Agent):

    def __init__ (self, name, adapter, team, robot, signposts):
        # Agent's identity.
        self.__name = name
        self.__team = team
        self.__adapter = adapter
        # Robot's proxy.
        self.__robot = robot

        # TODO: to obtain signposts from the camera.
        self.__signposts = {}
        self.__mobilities = {}
        self.__signpost = None
        self.__roles = [Robots.Role.Explorer]

        self.__mutex = thread.allocate_lock()
        self.__proxies = {}
        self.__destroyed = False

        # Load the fuzzy system.
        util = UtilFuzzy()
        util.loadFile(KB)
        self.__fuzzy = FuzzySystem(util.getSystemName())
        # Variables.
        for x in util.getVariables():
            self.__fuzzy.insertVar(x)
        # Rules.
        for i in range(len(util.getAntecedents())):
            self.__fuzzy.insertRule(util.getAntecedents()[i], util.getConsequences()[i])

        # TODO: to get mobilites from signposts.
        for i in range (0, len(signposts)):
            self.__signposts[i] = signposts[i]
            self.__mobilities[i] = random.Random().randint(0, 10)

        self.__proxies['self'] = Robots.AgentPrx.uncheckedCast(
            adapter.createProxy(self.__name))

        self.__auctioneer = Robots.AuctioneerPrx.uncheckedCast(
            adapter.getCommunicator().stringToProxy(
                'Auctioneer -t:tcp -h 192.168.161.92 -p 9898'))

        # Reference to the topic manager.
        try:
            #base = adapter.getCommunicator().stringToProxy('Robots.IceStorm/TopicManager')
            # TOCHANGE
            base = adapter.getCommunicator().stringToProxy('Robots/TopicManager:default -p 10000')
            self.__proxies['topicManager'] = IceStorm.TopicManagerPrx.checkedCast(base)
        except Ice.Exception, ex:
            sys.stdout.write('Invalid TopicManager: ' + str(ex))
            raise Ice.Exception

        # Team channel.
        try:
            self.__proxies[self.__team] = self.__proxies['topicManager'].retrieve(self.__team);
        except IceStorm.NoSuchTopic:
            self.__proxies[self.__team] = self.__proxies['topicManager'].create(self.__team)

        # Subscription to the team event channel.
        try:
            self.__proxies['pub'] = Robots.AgentPrx.uncheckedCast(
                self.__proxies[self.__team].subscribeAndGetPublisher(None, self.__proxies['self']))
            print Util.proxyToString(self.__proxies['self']) + ' subscribed with the ' + self.__team + ' channel.'
        except IceStorm.AlreadySubscribed, ex:
            self.__proxies['pub'] = Robots.AgentPrx.uncheckedCast(
                self.__proxies[self.__team].getPublisher())

    def inform (self, message, curr):

        # Announcement --> look for a signpost to lead.
        if isinstance(message, Robots.Announcement) and self.__signpost == None:

            mob = -1
            key = -1

            # Look for the best signpost to move.
            for k, s in self.__signposts.iteritems():
                for x in message.signposts:
                    if s == x and mob < self.__mobilities[k]:
                        mob = self.__mobilities[k]
                        key = k

            # Bid for the signpost with the best mobility.
            if key != -1:
                self.__auctioneer.receiveBid_async(AMI_Model_receiveBidI(),
                                                   Robots.Bid(self.__proxies['self'],
                                                            self.__signposts[key],
                                                            mob))

        # Close --> it becomes a leader. Go to the signpost.
        if isinstance(message, Robots.Close):
            self.__signpost = message.sp
            self.__roles.append(Robots.Role.Leader)
            print curr.id.name + "'s goal: [" + str(message.sp.pos.x) + ', ' + str(message.sp.pos.y) + ']'
            # TODO: to move the robot.
            # TODO: to a correct position around the signpost.

        # Finish --> look for a leader.
        if isinstance(message, Robots.Finish) and self.__signpost == None:
            print curr.id.name + ': I have to search a leader!'
            closestSP = self.closestSignPost()
            if closestSP:
                print 'Closest signpost is: [' + str(closestSP.pos.x) + ', ' + str(closestSP.pos.y) + ']'

    def closestSignPost (self):

        key, mob = -1, -1

        for k, v in self.__mobilities.iteritems():
            if v > mob:
                mob = v
                key = k

        try:
            return self.__signposts[key]
        except KeyError:
            return None

    def destroy (self, curr):
        self.__mutex.acquire()
        if self.__destroyed:
            raise Ice.ObjectNotExistException
        self.__destroyed = True

        # Unsubscribe with the eventChannel.
        self.__proxies['team'].unsubscribe(self.__proxies['self'])

        # Remove the servant from the object adapter.
        curr.adapter.remove(curr.id)
        self.__mutex.release()

    def isZombie (self):
        return self.__destroyed
